package intransix.osm.termite.gui.maplayer;

import javax.swing.*;
import javax.swing.table.*;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import intransix.osm.termite.app.maplayer.MapLayer;
import java.util.*;
import java.awt.Component;
import intransix.osm.termite.app.maplayer.MapLayerListener;

/**
 *
 * @author sutter
 */
public class LayerManagerPanel extends JPanel implements MapLayerListener {
	
	private final static int LAYER_COLUMN = 0;
	private final static int OPACITY_COLUMN = 1;
	
	private List<MapLayer> mapLayerList;

	/**
	 * Creates new form LayerManager
	 */
	public LayerManagerPanel() {
		initComponents();
		OpacityRenderer or = new OpacityRenderer();
		jTable1.setRowHeight(or.getPreferredSize().height);
		jTable1.setDefaultRenderer(Float.class,or);
		or = new OpacityRenderer();
		jTable1.setDefaultEditor(Float.class, or);
	}
	
	/** This method is called when the map layer state changes, including enable,
	 * visible and opacity. */
	@Override
	public void layerStateChanged(MapLayer mapLayer) {
		//for now just reload the list
		this.layerListChanged(mapLayerList);
	}
	
	/** This method is called when the content of a layer changes. */
	@Override
	public void layerContentChanged(MapLayer mapLayer) {
		//no action on content change
	}
	
	/** This method is called when the map layer list changes. This method
	 refreshes the layer list. */
	@Override
	public void layerListChanged(List<MapLayer> mapLayerList) {

		//save list
		this.mapLayerList = mapLayerList;
		
		//process new list
		DefaultTableModel model = (DefaultTableModel)jTable1.getModel();
		model.setRowCount(0);
		Object[] row = new Object[2];
		for(MapLayer layer:mapLayerList) {
			if((layer.getActiveState())&&(layer.isVisible())) {
				row[LAYER_COLUMN] = layer;
				row[OPACITY_COLUMN] = layer.getOpacity();
				model.addRow(row);
			}
		}
		this.repaint();
	}

	/**
	 * This method is called from within the constructor to initialize the form.
	 * WARNING: Do NOT modify this code. The content of this method is always
	 * regenerated by the Form Editor.
	 */
	@SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jScrollPane1 = new javax.swing.JScrollPane();
        jTable1 = new javax.swing.JTable();

        setLayout(new javax.swing.BoxLayout(this, javax.swing.BoxLayout.LINE_AXIS));

        jTable1.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {

            },
            new String [] {
                "Layer", "Opacity"
            }
        ) {
            Class[] types = new Class [] {
                java.lang.String.class, java.lang.Float.class
            };
            boolean[] canEdit = new boolean [] {
                false, true
            };

            public Class getColumnClass(int columnIndex) {
                return types [columnIndex];
            }

            public boolean isCellEditable(int rowIndex, int columnIndex) {
                return canEdit [columnIndex];
            }
        });
        jTable1.setRowHeight(70);
        jTable1.getTableHeader().setReorderingAllowed(false);
        jScrollPane1.setViewportView(jTable1);

        add(jScrollPane1);
    }// </editor-fold>//GEN-END:initComponents
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTable jTable1;
    // End of variables declaration//GEN-END:variables

	//==================
	// edit and render classes
	//==================
	
	public static class OpacityRenderer extends JSlider
                           implements TableCellRenderer, TableCellEditor,
						   ChangeListener {
		
		private final static int RANGE = 100;
		
		private List<CellEditorListener> listeners = new ArrayList<CellEditorListener>();
		private MapLayer activeLayer;

		public OpacityRenderer() {
			super(JSlider.HORIZONTAL,0,RANGE,RANGE);
			setOpaque(true); //MUST do this for background to show up.

			//labels
			this.setLabelTable(this.createStandardLabels(50));
			this.setPaintLabels(true);
			
			this.addChangeListener(this);
		}

		@Override
		public Component getTableCellRendererComponent(
								JTable table, Object opacity,
								boolean isSelected, boolean hasFocus,
								int row, int column) {
			int opacityInt = (int)(((Float)opacity).floatValue() * RANGE);
			this.setValue(opacityInt);
			return this;
		}

		@Override
		public Component getTableCellEditorComponent(JTable table,
										Object opacity,
										boolean isSelected,
										int row,
										int column) {
			activeLayer = (MapLayer)table.getModel().getValueAt(row,LAYER_COLUMN);
			int opacityInt = (int)(((Float)opacity).floatValue() * RANGE);
			this.setValue(opacityInt);
			return this;
		}
		
		@Override
		public Object getCellEditorValue() {
			return getOpacityValue();
		}
		
		public float getOpacityValue() {
			return this.getValue() * (1.0f / RANGE);
		}
		
		@Override
		public boolean isCellEditable(EventObject anEvent) {
			return true;
		}
		
		@Override
		public boolean shouldSelectCell(EventObject anEvent) {
			return true;
		}
		
		@Override
		public boolean stopCellEditing() {
			ChangeEvent changeEvent = new ChangeEvent(this);
			activeLayer = null;
			int cnt = listeners.size();
			for(int i = 0; i < cnt; i++) {
				listeners.get(i).editingStopped(changeEvent);
			}
			return true;
		}
		
		@Override
		public void cancelCellEditing() {
			ChangeEvent changeEvent = new ChangeEvent(this);
			activeLayer = null;
			int cnt = listeners.size();
			for(int i = 0; i < cnt; i++) {
				listeners.get(i).editingCanceled(changeEvent);
			}
		}
		
		@Override
		public void addCellEditorListener(CellEditorListener l) {
			if(!listeners.contains(l)) {
				listeners.add(l);
			}
		}
		
		@Override
		public void removeCellEditorListener(CellEditorListener l) {
			listeners.remove(l);
		}
		
		@Override 
		public void stateChanged(ChangeEvent ce) {
			if(activeLayer != null) {
				activeLayer.setOpacity(getOpacityValue());
			}
		}
	}
}
